/*
 * @Description: 类型定义
 * @Author: HuiSir<https://gitee.com/huisir001>
 * @Date: 2021-10-28 14:22:33
 * @LastEditTime: 2025-09-28 14:41:21
 */

/* eslint-disable @typescript-eslint/no-explicit-any */
import { VNode, Ref, DefineComponent } from "vue";
import {
  UploadRawFile,
  TableInstance,
  FormInstance,
  UploadFile,
  UploadFiles,
} from "element-plus";
export type Awaitable<T> = Promise<T> | T;

/**
 * 表格列配置
 */
export interface ICol {
  // 对应列的类型。 如果设置了selection则显示多选框；
  // 如果设置了 index 则显示该行的索引（从 1 开始计算）；
  // 如果设置了 expand 则显示为一个可展开的按钮
  type?: "selection" | "index" | "expand";

  // 仅对 type=selection 的列有效，
  // 返回值用来决定这一行的 CheckBox 是否可以勾选
  selectable?: (row: any, index: number) => boolean;

  //列标题
  label?: string;

  // 对应列内容的字段名
  prop?: string;

  // 用来格式化内容，返回值为当前行的展示内容
  formatter?: (
    row: Record<string, unknown>,
    column: Record<string, unknown>,
    cellValue: any,
    index: number
  ) => string | VNode | VNode[];

  // 对应列的宽度
  width?: string | number;

  // 列对齐方式
  align?: "left" | "center" | "right";

  // 列的自定义 className
  className?: string;

  // 当前列标题的自定义类名
  labelClassName?: string;

  // 对应列的最小宽度， 与 width 的区别是
  // width 是固定的，
  // min-width 会把剩余宽度按比例分配给设置了 min-width 的列
  minWidth?: string | number;

  // 列是否固定在左侧或者右侧， true 表示固定在左侧
  fixed?: true | "left" | "right";

  // 对应列是否可以排序
  // 'custom'：代表用户希望远程排序，需要监听 Table 的 sort-change 事件
  // 相关事件文档：https://element-plus.gitee.io/zh-CN/component/table.html#table-events
  sortable?: true | false | "custom";

  // 指定数据排序方案，与数组sort方法类似
  sortMethod?: (a: any, b: any) => number;

  // 指定数据按照哪个属性进行排序，仅当sortable设置为true且没有设置sort-method的时候有效。
  // 如果为数组，则先按照第 1 个属性排序，如果第 1 个相等，再按照第 2 个排序，以此类推
  sortBy?: string | string[];

  // 数据过滤的选项， 数组格式，数组中的元素需要有 text 和 value 属性。
  // 需要监听 Table 的 filter-change 事件
  filters?: Array<{ text: string; value: any }>;

  // 当内容过长被隐藏时显示 tooltip
  showOverflowTooltip?: boolean;

  // 允许默认插槽，且已定义插槽模板，如设置 slot="todo"
  // <template #todo="scope">...</template>
  // 如设置 slot="default"
  // <template #default="scope">...</template>
  slot?: string;

  // 使用内置行按钮，若不设则不使用，在参数slot与useRowBtns同时存在时，useRowBtns优先
  // 若useRowBtns的值为true，则使用默认按钮组["edit","del"]
  useRowBtns?: ("edit" | "detail" | "add" | "del")[] | boolean;

  // 允许表头插槽，且已定义表头插槽模板
  // <template #header>...</template>
  slotHead?: string;

  /**
   * 使用模糊搜索(表头)，这里默认会使用slotHead将模糊搜索输入框插入
   * 使用此参数，slotHead配置将无效
   * 不分页情况下可以使用本地模糊搜索
   */
  useFuzzySearch?: boolean;
  /**
   * 模糊搜索输入占位
   */
  fuzzySearchPlaceholder?: string;

  // 表头标题带帮助提示
  helpTip?: string;

  // 隐藏
  hide?: boolean;
}

/**
 * 表格工具栏
 */
export interface ITableTool {
  title: string;
  name: TOptionOfTools;
  icon?: string;
  disabled?: boolean;
  // 类型（按钮色）：默认primary，只针对position为left位置有效
  type?: "primary" | "success" | "info" | "warning" | "danger" | "text";
  dropdown?: boolean; // 是否为下拉菜单
}

/**
 * 表格工具左右按钮组
 */
export type TUseTableTools = () => { left: ITableTool[]; right: ITableTool[] };

/**
 * 表格工具配置传参
 */
export type TOptionOfTools =
  | "add"
  | "delete"
  | "fold" // 展开折叠
  | "export"
  | "search"
  | "refresh"
  | "cols";

/**
 * 表单验证
 */
export interface IFormRule {
  required?: boolean;
  message?: string;
  trigger?: "blur" | "change";
  type?: "date" | "array" | "string" | "number";
  min?: number;
  max?: number;
  validator?: (rule: any, value: any, callback: (error?: Error) => any) => any;
  pattern?: RegExp;
}

/**
 * 详情弹窗配置
 */
export interface IDetailOption {
  // 名称
  label: string;
  // 字段
  key: string;
  // 用来格式化内容，返回值为当前数据的展示内容
  formatter?: (params: Record<string, unknown>) => any;
  // 允许插槽
  slot?: string;
}

/**
 * 表单项配置
 */
export interface IFormOption {
  /**
   * 表单项名称，可不设，则不展示label
   */
  label?: string;
  /**
   * 表单项组件类型
   */
  component?: string;
  /**
   * 字段
   */
  key: string;
  // 验证
  rules?: IFormRule | IFormRule[];
  /**
   * 下拉框或多选单选的选项
   */
  options?: Array<{ label: string; value: string | number }>;
  // 默认值
  default?: any;
  /**
   * 表单项说明，会展示在表单项下方，可是是函数
   */
  desc?: string | ((formData: Record<string, any>) => string);
  /**
   * 表单项其他属性
   */
  props?: {
    placeholder?: string;
    /**
     * 输入框类型：如 text/password；
     * 日期类型：year/month/date/dates/datetime/week/datetimerange/daterange/monthrange
     */
    type?: string;
    /**
     * input 用来格式化内容，只有当 input的类型type 是"text"时才能工作
     */
    formatter?: (value: string | number) => string;
    /**
     * 输入框是否允许浏览器自动填入，默认在表单组件中设定为off或new-password，可在此设置覆盖
     */
    autocomplete?: "on" | "off" | "new-password";
    rangeSeparator?: string;
    startPlaceholder?: string;
    endPlaceholder?: string;
    showPassword?: boolean; //展示密码显隐按钮
    readonly?: boolean;
    disabled?: boolean;
    /**
     * 选择框是否可筛选
     */
    filterable?: boolean;
    /**
     * 显示在输入框中的格式
     */
    format?: string;
    defaultValue?: typeof Date;
    defaultTime?: Array<typeof Date>;
    /**
     * 绑定值的格式。不指定则绑定值为 Date 对象: (YYYY-MM-DD|x),x为毫秒数
     */
    valueFormat?: string;
    /**
     * 设置快捷选项，需要传入数组对象
     */
    shortcuts?: Array<{ text: string; value: typeof Date | typeof Function }>;
    /**
     * 是否多选（select类型或文件上传）
     */
    multiple?: boolean;
    /**
     * 是否折叠多选（select类型）
     */
    collapseTags?: boolean;
    /**
     * 开关属性
     */
    activeText?: string;
    inactiveText?: string;
    activeValue?: string | number;
    inactiveValue?: string | number;
    /**
     * 数字输入框控制按钮位置
     */
    controlsPosition?: "right";
    /**
     * 富文本编辑器配置
     */
    uploadImageConfig?: RichEditorUploadImageConfig;
    // 数字输入框 input-number
    precision?: number; // 数字输入框保留小数
    step?: number; // 数字输入框新增步长
    // 如下为文件上传参数
    /**
     * 文件上传类型，默认array
     */
    fieldType?: "string" | "array";
    /**
     * 允许上传的文件类型，如 image/png, image/jpeg, image/gif, image/svg+xml
     */
    accept?: string;
    /**
     * 列表展示方式（这里已被重构），默认text
     */
    listType?: "text" | "picture-card";
    action?: string;
    headers?: Record<string, any>;
    /**
     * 是否自动上传
     */
    autoUpload?: boolean;
    /**
     * 是否允许url插入，默认是
     */
    allowUrlInsert?: boolean;
    /**
     * 上传的文件字段名 默认file
     */
    name?: string;
    limit?: number;
    /**
     * 文件最大尺寸，单位：字节, 不传不限制
     */
    maxFileSize?: number;
    /**
     * 是否隐藏上传按钮当上传数量足够limit值时
     */
    showTextBtnIfFilesMoreThanLimit?: boolean;
    /**
     * 上传的额外字段
     */
    data?:
      | Record<string, any>
      | Awaitable<Record<string, any>>
      | ((rawFile: UploadRawFile) => Awaitable<Record<string, any>>);
    /**
     * 回调（参数是请求回的内容），需要return上传后的文件地址，这里只支持单文件上传，所以返回的是单个文件的url
     */
    callback?: (res: any) => string | void | null | boolean;
  };
  /**
   * 插槽-自定义表单项
   */
  slot?: string;
  /**
   * 显隐,默认显示,这里加入函数模式，用于手动加入条件进行控制
   */
  hide?: boolean | ((formData: Record<string, any>) => boolean);
  /**
   * 输入项标题宽度
   */
  labelWidth?: string | number;
  /**
   *  输入框宽度
   */
  inputWidth?: string | number;
  /**
   * 输入框后添加文字
   */
  suffix?: string;
}

/**
 * 表单弹窗固定参数
 */
export interface IFormDialogProps {
  /**
   * 弹窗标题，默认"编辑"
   */
  title?: string;
  /**
   * 弹窗距顶部距离，默认15%
   */
  top?: string | number;
  /**
   * 弹窗宽度，默认500
   */
  width?: string | number;
  /**
   * 表单标签宽度，默认80
   */
  labelWidth?: string | number;
  /**
   * 表单项输入框宽度，默认100%
   */
  inputWidth?: string | number;
  /**
   * 表单整体宽度，默认100%
   */
  formWidth?: string | number;
  /**
   * 表单水平居中，默认false
   */
  formCenter?: boolean;
  /**
   * 是否全屏显示表单弹窗，默认false
   */
  fullscreen?: boolean;
}

/**
 * 内置表格行按钮组 row-btns 组件配置项
 */
export interface IRowBtnsOptions {
  /**
   * 编辑弹窗固定参数
   */
  editDialogProps?: IFormDialogProps;
  /**
   * 新增弹窗固定参数
   */
  addDialogProps?: IFormDialogProps;
  /**
   * 详情弹窗标题
   */
  detailDialogTitle?: string;
  /**
   * 详情弹窗表单配置
   */
  detailOptions?: IDetailOption[];
  /**
   * 新增弹窗表单配置
   */
  addFormOptions?: IFormOption[];
  /**
   * 编辑弹窗表单配置
   */
  editFormOptions?: IFormOption[];
  /**
   * 详情弹窗弹出前钩子，用于处理表单默认展示的数据
   */
  beforeShowDetailDialog?: (
    rowData: Ref<Record<string, any>>,
    detailOptions: Ref<IDetailOption[]>
  ) => Awaitable<void>;
  /**
   * 编辑弹窗弹出前钩子，用于处理表单默认展示的数据
   */
  beforeShowEditDialog?: (
    rowData: Ref<Record<string, any>>,
    editFormOptions: Ref<IFormOption[]>
  ) => Awaitable<void>;
  /**
   * 新增弹窗弹出前钩子，用于处理表单默认展示的数据
   */
  beforeShowAddDialog?: (
    rowData: Ref<Record<string, any>>,
    addFormOptions: Ref<IFormOption[]>
  ) => Awaitable<void>;
  /**
   * 文件上传change事件
   */
  uploadChange?: (
    uploadParams: UploadEventParams,
    form: UploadChangeForm
  ) => void;
}

/**
 * 表单工具栏配置项
 */
export interface IToolsOptions {
  /**
   * 工具列表
   */
  tools?: TOptionOfTools[];
  /**
   * 搜索表单初始状态，不设为默认隐藏
   */
  showSearchFormInitial?: boolean;
  /**
   * 搜索表单参数，若存在搜索表单，则该对象必传，
   * 可传空对象
   */
  searchFormParams?: Record<string, any>;
  /**
   * 搜索表单配置项
   */
  searchFormOptions?: IFormOption[];
  /**
   * 搜索表单标签宽度,默认80
   */
  searchFormLabelWidth?: string | number;
  /**
   * 新增弹窗固定参数
   */
  addDialogProps?: IFormDialogProps;
  /**
   * 新增弹窗表单配置
   */
  addFormOptions?: IFormOption[];
  /**
   * 新增弹窗默认数据
   */
  addFormDefaultData?: Record<string, any>;
  /**
   * 表单项加载钩子
   * 这里可以对表单项数据进行处理或执行请求
   */
  beforeSearchFormLoad?: (
    formData: Ref<Record<string, unknown>>,
    formOptions: Ref<IFormOption[]>
  ) => Awaitable<void>;
  /**
   * 新增弹窗弹出前钩子，用于处理表单默认展示的数据
   */
  beforeShowAddDialog?: (
    formData: Ref<Record<string, any>>,
    addFormOptions: Ref<IFormOption[]>
  ) => Awaitable<void>;
  /**
   * 文件上传change事件
   */
  uploadChange?: (
    uploadParams: UploadEventParams,
    form: UploadChangeForm
  ) => void;
}

/**
 * 富文本编辑器上传图片配置接口
 * @param server string 接口路径，必填
 * @param fieldName string | undefined 表单字段名（默认为 file）
 * @param headers Record<string, string> | undefined 请求头，设置token等参数
 * @param meta Record<string, unknown> | undefined 额外参数（如文件分类）
 * @param maxFileSize number | undefined 上传大小限制默认 10MB
 * @param base64LimitSize number | undefined 多大图片可以转base64 默认 60*1024 (60kb)
 * @param callback (res: any) => string 必传，钩子函数，返回图片路径
 */
export interface RichEditorUploadImageConfig {
  server: string;
  fieldName?: string;
  headers?: Record<string, string>;
  meta?: Record<string, unknown>;
  maxFileSize?: number;
  base64LimitSize?: number;
  callback: (res: any) => string | void | null | boolean;
}

/**
 * 手动上传文件结果
 */
export interface UploadSubmitResult {
  response: Record<string, any> | string;
  status: "rejected" | "fulfilled";
  uid: number;
}

/**
 * 手动文件上传选择事件及自动上传完成事件回调参数
 */
export interface UploadEventParams {
  uploadFile?: UploadFile;
  uploadFiles: UploadFiles;
  formItemKey?: string;
}

/**
 * 编辑弹窗-文件上传change事件第二参
 */
export interface UploadChangeForm {
  data: Ref<Record<string, unknown>>;
  options: Ref<IFormOption[]>;
}

/**
 * 编辑弹窗提交按钮回调参数
 * @cb closeLoading -> 按钮loading关闭
 * @cb closeDialog -> 关闭弹窗
 */
export interface SubmitCallbacks {
  /**
   * 表单验证，原先是自动验证，这里改为手动验证
   */
  validate: () => Awaitable<boolean>;
  /**
   * 关闭弹窗按钮loading
   */
  closeLoading: () => void;
  /**
   * 关闭弹窗
   */
  closeDialog: () => void;
  /**
   * 表单上传组件手动执行上传
   */
  uploadSubmit: () => Promise<
    {
      key: string;
      result: UploadSubmitResult[];
    }[]
  >;
}

/**
 * 编辑弹窗提交按钮回调参数
 * @cb closeLoading -> 按钮loading关闭
 */
export interface DeleteCallbacks {
  closeLoading: () => void;
}

/**
 * 表格扩展
 */
export interface FyTableInstance extends TableInstance {
  selection: any[];
}

/**
 * 表单原型
 */
export interface FyFormInstance extends DefineComponent {
  elForm: FormInstance;
  validate: () => Awaitable<boolean>;
  setModelVal: (val: unknown, key: string) => void;
  resetLoading: Ref<boolean>;
  submitLoading: Ref<boolean>;
  submit: () => void;
  reset: () => void;
  clear: () => void;
  uploadSubmit: () => Promise<{
    key: string;
    result: UploadSubmitResult[];
  }>;
}

/**
 * 列表（数组）编辑表格表单验证规则
 */
export interface ListEditInputRule {
  required?: boolean;
  message?: string;
  validator?: (value: any) => boolean | string;
  min?: number;
  max?: number;
  pattern?: RegExp;
}

/**
 * 列表（数组）编辑表格列配置项
 */
export interface ListEditTableCol {
  prop: string;
  label: string;
  width?: string | number;
  editable?: boolean;
  editorType?: "input" | "select" | "number" | "date";
  options?: Array<{ value: any; label: string }>;
  rules?: ListEditInputRule | Array<ListEditInputRule>;
  min?: number;
  max?: number;
  minWidth?: string | number;
  fixed?: true | "left" | "right";
  slot?: string;
}

/**
 * 列表（数组）编辑表格组件props
 */
export interface ListEditTableProps {
  columns: ListEditTableCol[];
  data: Array<Record<string, any>>;
  showActionColumn?: boolean;
  showSaveButton?: boolean;
  showDeleteButton?: boolean;
  showSaveAllButton?: boolean;
  addRowPosition?: "lastRow" | "bottom";
}

/**
 * 列表操作项
 */
export interface ListAction {
  /**
   * 唯一标识
   */
  name?: string;
  /**
   * 按钮类型
   */
  type?: "primary" | "success" | "info" | "warning" | "danger" | "text";
  /**
   * 按钮图标
   */
  icon?: string | boolean;
  /**
   * 按钮名称
   */
  title?: string;
}

/**
 * 列表组件props
 */
export interface ListProps {
  icon?: string | boolean;
  rightIcon?: string | boolean;
  iconSize?: number;
  rightIconSize?: number;
  list?: ListItem[];
  actions?: ListAction[];
  size?: "small" | "medium" | "large";
  border?: boolean;
  /**
   * 列表项间距
   */
  rowSpace?: number;
  /**
   * 列表项圆角
   */
  rowRadius?: number;
  /**
   * 列表项背景颜色
   */
  rowBgColor?: string;
  /**
   * 是否使用指针光标
   */
  useCursorPointer?: boolean;
  /**
   * 是否开启加载更多
   */
  showLoadMore?: boolean;
  /**
   * 加载更多loading状态
   */
  loadMoreLoading?: boolean;
  /**
   * 列表项激活背景颜色
   */
  highlightBgColor?: string;
  /**
   * 列表项激活文本颜色
   */
  highlightColor?: string;
}

/**
 * 列表项
 */
export interface ListItem extends Record<string, any> {
  icon?: string | boolean;
  rightIcon?: string | boolean;
  title?: string;
  desc?: string;
  actions?: ListAction[];
  disabled?: boolean;
}
